pthread

您所在的位置:网站首页 cleanup和clean out的区别 pthread

pthread

2024-07-11 08:46:56| 来源: 网络整理| 查看: 265

一、为什么会有pthread_cleanup_push与pthread_cleanup_pop:

一般来说,Posix的线程终止有两种情况:正常终止和非正常终止。线程主动调用pthread_exit()或者从线程函数中return都将使线程正常退出,这是可预见的退出方式;非正常终止是线程在其他线程的干预下,或者由于自身运行出错(比如访问非法地址)而退出,这种退出方式是不可预见的。

不论是可预见的线程终止还是异常终止,都会存在资源释放的问题,在不考虑因运行出错而退出的前提下,如何保证线程终止时能顺利的释放掉自己所占用的资源,特别是锁资源,就是一个必须考虑解决的问题。

最经常出现的情形是资源独占锁的使用:线程为了访问临界资源而为其加上锁,但在访问过程中被外界取消,如果线程处于响应取消状态,且采用异步方式响应,或者在打开独占锁以前的运行路径上存在取消点,则该临界资源将永远处于锁定状态得不到释放。外界取消操作是不可预见的,因此的确需要一个机制来简化用于资源释放的编程。

在POSIX线程API中提供了一个pthread_cleanup_push()/pthread_cleanup_pop()函数对用于自动释放资源 --从pthread_cleanup_push()的调用点到pthread_cleanup_pop()之间的程序段中的终止动作(包括调用 pthread_exit()和取消点终止)都将执行pthread_cleanup_push()所指定的清理函数。API定义如下:

void pthread_cleanup_push(void (*routine) (void  *),  void *arg)void pthread_cleanup_pop(int execute)

pthread_cleanup_push()/pthread_cleanup_pop()采用先入后出的栈结构管理,void routine(void *arg)函数在调用pthread_cleanup_push()时压入清理函数栈,多次对pthread_cleanup_push()的调用将在清理函数栈中形成一个函数链,在执行该函数链时按照压栈的相反顺序弹出。execute参数表示执行到pthread_cleanup_pop()时是否在弹出清理函数的同时执行该函数,为0表示不执行,非0为执行;这个参数并不影响异常终止时清理函数的执行。

二、pthread_cleanup_push与pthread_cleanup_pop干什么用:

 

比如thread1: 执行 pthread_mutex_lock(&mutex); //一些会阻塞程序运行的调用,比如套接字的accept,等待客户连接 sock = accept(......);            //这里是随便找的一个可以阻塞的接口 pthread_mutex_unlock(&mutex); 这个例子中,如果线程1执行accept时,线程会阻塞(也就是等在那里,有客户端连接的时候才返回,或则出现其他故障),线程等待中...... 这时候线程2发现线程1等了很久,不赖烦了,他想关掉线程1,于是调用pthread_cancel()或者类似函数,请求线程1立即退出。 这时候线程1仍然在accept等待中,当它收到线程2的cancel信号后,就会从accept中退出,然后终止线程,注意这个时候线程1还没有执行: pthread_mutex_unlock(&mutex); 也就是说锁资源没有释放,这回造成其他线程的死锁问题。 所以必须在线程接收到cancel后用一种方法来保证异常退出(也就是线程没达到终点)时可以做清理工作(主要是解锁方面),pthread_cleanup_push与pthread_cleanup_pop就是这样的。 pthread_cleanup_push(some_clean_func,...) pthread_mutex_lock(&mutex); //一些会阻塞程序运行的调用,比如套接字的accept,等待客户连接 sock = accept(......);            //这里是随便找的一个可以阻塞的接口 pthread_mutex_unlock(&mutex); pthread_cleanup_pop(0); return NULL; 上面的代码,如果accept被cancel后线程退出,会自动调用some_clean_func函数,在这个函数中你可以释放锁资源。如果accept没有被cancel,那么线程继续执行,当pthread_mutex_unlock(&mutex);表示线程自己正确的释放资源了,而执行pthread_cleanup_pop(0);也就是取消掉前面的some_clean_func函数。接着return线程就正确的结束了。 不晓得你明白没,通俗点就是: pthread_cleanup_push注册一个回调函数,如果你的线程在对应的pthread_cleanup_pop之前异常退出(return是正常退出,其他是异常),那么系统就会执行这个回调函数(回调函数要做什么你自己决定)。但是如果在pthread_cleanup_pop之前没有异常退出,pthread_cleanup_pop就把对应的回调函数取消了, 关于取消点的解释: 比如你执行:         printf("thread sleep\n");         sleep(10);         printf("thread wake...\n"); 在sleep函数中,线程睡眠,结果收到cancel信号,这时候线程从sleep中醒来,但是线程不会立刻退出。这是应为pthread与C库方面的原因(具体是啥我也不清楚),pthread的建议是,如果一个函数是阻塞的,那么你必须在这个函数前后建立取消点,比如:         printf("thread sleep\n");         pthread_testcancel();         sleep(10);         pthread_testcancel();         printf("thread wake...\n");

这样,就添加了两个取消掉。在执行到pthread_testcancel的位置时,线程才可能响应cancel退出进程。

三、需要注意:

原型很简单,功能跟atexit()差不多,只不过一个是线程一个是进程。用来设置在push/pop内线程退出时要做的事情。

pthread_cleanup_push与pthread_cleanup_pop是成对的宏实现的push与pop一定是成对出现的,其实push中包含"{"而pop中包含"}",少一个不行。 “线程取消函数”即线程被取消或者下面描述的情况发生时自动调用的函数。它一般用于释放一些资源,比如释放锁,以免其它的线程永远 也不能获得锁,而造成死锁。 pthread_cleanup_push()函数执行压栈清理函数的操作,而pthread_cleanup_pop()函数执行从栈中删除清理函数的操作。

在下面三种情况下,pthread_cleanup_push()压栈的“清理函数”会被调用:

1, 线程调用pthread_exit()函数,而不是直接return.

2, 响应取消请求时,也就是有其它的线程对该线程调用pthread_cancel()函数。

3, 本线程调用pthread_cleanup_pop()函数,并且其参数非0

注意: 1.当pthread_cleanup_pop()函数的参数为0时,仅仅在线程调用pthread_exit函数或者其它线程对本线程调用 

     pthread_cancel函数时,才在弹出“清理函数”的同时执行该“清理函数”。

2.注意pthread_exit终止线程与线程直接return终止线程的区别,调用return函数是不会在弹出“清理函数”的同时执行该“清理函数的。

3 .pthread_cleanup_push()函数与pthread_cleanup_pop()函数必须成对的出现在同一个函数中。

4.在线程宿主函数中主动调用return,如果return语句包含在pthread_cleanup_push()/pthread_cleanup_pop()对中,则不会引起清理函数的执行,反而会导致segment fault。 push进去的函数可能在以下三个时机执行: 1,显示的调用pthread_exit(); 或 2,在cancel点线程被cancel。 或 3,pthread_cleanup_pop()的参数不为0时。 以上动作都限定在push/pop涵盖的代码内。

 

#include #include #include #include void * thr_fn(void *); void cleanup(void *); int main(int argc,char ** argv) { pthread_t tid; int err; void * tret; err=pthread_create(&tid,NULL,thr_fn,NULL); if(err!=0) printf("create thread error: %s\n",strerror(err)); err=pthread_join(tid,&tret); if(err!=0) printf("thread join error: %s\n",strerror(err)); printf("thread exit code %d\n",(int)tret); return 0; } void cleanup(void * arg) { printf("clean : %s\n",(char *)arg); } void * thr_fn(void * arg) { printf("thread push start.\n"); pthread_cleanup_push(cleanup,"thread first handler"); pthread_cleanup_push(cleanup,"thread second handler"); printf("thread push over.\n"); pthread_exit((void *)1); pthread_cleanup_pop(0); pthread_cleanup_pop(0); pthread_exit((void *)2); } 额外的知识: 对于cancel信号,线程有两种方法: 忽略,和响应。默认是响应

接收到cancel信号,线程有两种处理类型: 立即响应 和 延迟响应(在最近的取消点响应),默认是延迟响应

参考:http://blog.csdn.net/caianye/article/details/5912172

http://blog.chinaunix.net/uid-20583479-id-1919902.html

http://blog.csdn.net/slj_win/article/details/7267483



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭